package com.jilujia.domain.question.service;

import java.util.List;

import net.sf.ehcache.Ehcache;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.data.domain.Page;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jilujia.domain.question.Answer;
import com.jilujia.domain.question.AnswerComment;
import com.jilujia.domain.question.AnswerCommentManager;
import com.jilujia.domain.question.AnswerManager;
import com.jilujia.domain.question.Question;
import com.jilujia.domain.question.QuestionManager;
import com.jilujia.domain.question.QuestionTag;
import com.jilujia.domain.question.QuestionTagManager;
import com.jilujia.domain.question.QuestionTagRelationManager;
import com.jilujia.domain.question.repository.AnswerCommentRepository;
import com.jilujia.domain.question.repository.AnswerRepository;
import com.jilujia.domain.question.repository.QuestionRepository;
import com.jilujia.domain.question.repository.QuestionTagRepository;
import com.jilujia.domain.region.Region;
import com.jilujia.domain.user.UserVoteAnswerManager;
import com.jilujia.domain.user.UserVoteQuestionManager;
import com.jilujia.framework.domain.AbstractService;
import com.jilujia.framework.domain.SearchCriteria;
import com.jilujia.web.CacheConstants;

/**
 * A JPA-based implementation of the Booking Service. Delegates to a JPA entity
 * manager to issue data access calls against the backing repository. The
 * EntityManager reference is provided by the managing container (Spring)
 * automatically.
 */
@Service("questionService")
@Transactional(readOnly = true)
public class QuestionServiceImpl extends AbstractService implements QuestionService {

	private static final Logger LOG = LoggerFactory.getLogger(QuestionServiceImpl.class);

	@Autowired
	private QuestionRepository questionRepository;

	@Autowired
	private AnswerRepository answerRepository;

	@Autowired
	private AnswerCommentRepository answerCommentRepository;

	@Autowired
	private QuestionTagRepository questionTagRepository;

	@Autowired
	private CacheManager cacheManager;

	public Page<Question> findQuestionsByCriteria(SearchCriteria criteria) {
		LOG.debug("findQuestions invoked");
		Page<Question> questions = questionRepository.findAll(criteria.getSortedPageRequest());

		return questions;
	}

	public Page<Answer> findAnswersByCriteria(Long questionId, SearchCriteria criteria) {
		Page<Answer> answers = answerRepository.findAnswersByQuestionId(questionId, criteria.getPageRequest());

		return answers;
	}

	public Page<AnswerComment> findAnswerCommentsByCriteria(Long answerId, SearchCriteria criteria) {

		Page<AnswerComment> answerComments = answerCommentRepository.findAnswerCommentsByAnswerId(answerId,
				criteria.getPageRequest());

		return answerComments;
	}

	public Page<Question> findQuestionsByTagCriteria(String tagName, SearchCriteria criteria) {
		Page<Question> questions = questionRepository.findQuestionsByTag(tagName, criteria.getPageRequest());
		return questions;
	}

	public Page<QuestionTag> findQuestionTagsByCriteria(SearchCriteria criteria) {
		Page<QuestionTag> questionTags = questionTagRepository.findAll(criteria.getPageRequest());
		return questionTags;
	}

	public List<QuestionTag> findAssociatedQuestionTags(QuestionTag tag) {
		List<QuestionTag> questionTags = questionTagRepository.findAssociatedQuestionTags(tag.getId(),
				SearchCriteria.getTop10PageRequest());
		return questionTags;
	}

	public Question createQuestion() {
		Question question = new Question();
		return question;
	}

	@Transactional
	public Question persistQuestion(Question questionVo, Long userId) {

		// 保存question
		QuestionManager questionManager = getApplicationContext().getBean(QuestionManager.class);
		Question questionPo = questionManager.saveQuestion(questionVo, userId);

		// 保存tags
		for (String tagName : questionVo.getTags()) {
			// 保存tag并使其count+1
			QuestionTagManager questionTagManager = getApplicationContext().getBean(QuestionTagManager.class);
			questionTagManager.saveTag(tagName);
			QuestionTag questionTag = questionTagManager.getInstance();

			// 保存tag和question的关系
			QuestionTagRelationManager questionTagRelationManager = getApplicationContext().getBean(
					QuestionTagRelationManager.class);
			questionTagRelationManager.saveRelation(questionPo.getId(), questionTag.getId());

		}

		return questionPo;

	}

	public Question findQuestionById(Long id) {
		Question question = questionRepository.findOne(id);
		return question;
	}

	public Answer createAnswer(Question question) {
		Answer answer = new Answer();
		answer.setQuestion(question);
		return answer;
	}

	@Transactional
	public Answer persistAnswer(Answer answerVo, Long userId) {

		// 保存Answer
		AnswerManager answerManager = getApplicationContext().getBean(AnswerManager.class);
		Answer answerPo = answerManager.saveAnswer(answerVo, userId);

		// Question answercount + 1
		QuestionManager questionManager = getApplicationContext().getBean(QuestionManager.class);
		questionManager.setInstance(answerPo.getQuestion());
		questionManager.addAnswerCount();

		return answerPo;
	}

	public AnswerComment createAnswerComment() {
		AnswerComment answerComment = new AnswerComment();
		return answerComment;
	}

	@Transactional
	public AnswerComment persistAnswerComment(AnswerComment answerCommentVo, Long userId) {

		AnswerCommentManager answerCommentManager = getApplicationContext().getBean(AnswerCommentManager.class);

		AnswerComment answerCommentPo = answerCommentManager.saveAnswerComment(answerCommentVo, userId);

		// Answer commentcount + 1
		AnswerManager answerManager = getApplicationContext().getBean(AnswerManager.class);
		answerManager.setInstance(answerCommentPo.getAnswer());
		answerManager.addCommentCount();

		return answerCommentPo;
	}

	public QuestionTag findQuestionTagByName(String tagName) {
		QuestionTag questionTag = questionTagRepository.findQuestionTagByName(tagName);
		return questionTag;
	}

	public List<QuestionTag> findTagsByQuestionId(Long questionId) {
		List<QuestionTag> tagList = questionTagRepository.findQuestionTagsByQuestionId(questionId);
		return tagList;
	}

	@Transactional
	public void voteAnswer(Long answerId, Long userId, boolean useful) {
		// 记录投票
		UserVoteAnswerManager userVoteAnswerManager = getApplicationContext().getBean(UserVoteAnswerManager.class);
		userVoteAnswerManager.vote(userId, answerId, useful);

		// 更新answer的VoteCount
		AnswerManager answerManager = getApplicationContext().getBean(AnswerManager.class);
		answerManager.findOneById(answerId);
		answerManager.changeVoteCount(useful);

		Question question = answerManager.getInstance().getQuestion();
		QuestionManager questionManager = getApplicationContext().getBean(QuestionManager.class);
		questionManager.setInstance(question);
		questionManager.changeAnswerVoteSum();

	}

	@Transactional
	public void voteQuestion(Long questionId, Long userId, boolean useful) {
		// 记录投票
		UserVoteQuestionManager userVoteQuestionManager = getApplicationContext().getBean(UserVoteQuestionManager.class);
		userVoteQuestionManager.vote(userId, questionId, useful);

		// 更新question的VoteCount
		QuestionManager questionManager = getApplicationContext().getBean(QuestionManager.class);
		questionManager.findOneById(questionId);
		questionManager.changeVoteCount(useful);

	}

	public List<Question> findTop10QuestionsByRegion(Region region) {
		List<Question> questions = questionRepository.findQuestionsByRegion(region.getId(),
				SearchCriteria.getTop10PageRequest());
		return questions;
	}

	public Integer findQuestionViewCountById(Long questionId) {
		QuestionManager questionManager = getApplicationContext().getBean(QuestionManager.class);
		Integer viewCount = questionManager.getViewCount(questionId);
		questionManager.addViewCount(questionId);
		return viewCount;
	}

	// TODO 更新pop还没定怎么做
	@Scheduled(cron = "0 0/2 * * * ?")
	@Transactional
	public void refleshQuestionViewCount() {
		LOG.debug("refleshQuestionViewCount begin");
		Ehcache ehcache = (Ehcache) cacheManager.getCache(CacheConstants.QUESTIONS_VIEWCOUNT_CACHENAME).getNativeCache();
		for (Object key : ehcache.getKeys()) {
			String strKey = (String) key;
			Integer viewCount = (Integer) ehcache.get(strKey).getObjectValue();
			String questionId = strKey.substring(strKey.indexOf(":") + 1);
			LOG.debug("refleshQuestionViewCount:" + questionId + ":" + viewCount);

			QuestionManager questionManager = getApplicationContext().getBean(QuestionManager.class);
			questionManager.saveViewCount(Long.valueOf(questionId), viewCount);
			// use strkey and followcount batch update count in hotel
		}
		LOG.debug("refleshQuestionViewCount end");
	}

}